package team.scau.laboratory_repair.service;

import lombok.extern.apachecommons.CommonsLog;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.history.HistoricVariableInstance;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import team.scau.laboratory_repair.common.activiti.dto.RepairProcDto;
import team.scau.laboratory_repair.common.activiti.dto.RepairTaskDto;
import team.scau.laboratory_repair.common.activiti.listener.LabRepairHandlerRe;
import team.scau.laboratory_repair.common.constant.ConstantRole;
import team.scau.laboratory_repair.common.json.PoToDto;
import team.scau.laboratory_repair.common.utils.StringTool;
import team.scau.laboratory_repair.modules.po.*;

import java.util.*;

/**
 * @author 30254
 * creadtedate:2018/10/24
 */
@Service
@CommonsLog
public class RepairService {
    @Autowired
    private AreaService areaService;

    @Autowired
    private RecordService recordService;

    @Autowired
    private NoteService noteService;

    @Autowired
    private RecordPhotoService recordPhotoService;

    @Autowired
    private ActivitiService activitiService;

    @Autowired
    private LabRepairHandlerRe handlerRe;

    @Autowired
    private UserService userService;

    @Autowired
    private PoToDto poToDto;

    private static final String UNCLAIM_TIP = "撒手了";
    private static final String CLAIM_TIP = "接手了";

    @Transactional(rollbackFor = Exception.class)
    public void submit(Record record, String[] urls) throws Exception {
        recordService.save(record);
        if (urls != null) {
            for (String url : urls) {
                    RecordPhoto photo = new RecordPhoto();
                    photo.setUrl(url);
                    photo.setRecordId(record.getId());
                    recordPhotoService.save(photo);
                }
        }
        HashMap<String, Object> data = new HashMap<>();
        Area area = areaService.findById(record.getArea());
        User user = userService.findById(area.getManager());
        String phone = user.getPhoneNumber();
        data.put("recordId", record.getId());
        data.put("phone", phone);
        ProcessInstance instance = activitiService.startProc("labRepairRe");
        String taskId = activitiService.getUserTaskByProcId(instance.getProcessInstanceId()).getId();
        activitiService.completeWithData(taskId, data);

    }

    @Transactional(rollbackFor = Exception.class)
    public void claim(String taskId, Long recordId, Long staffId, Boolean self) throws Exception {
        HashMap<String, Object> data = new HashMap<>();
        data.put("staffId", staffId.toString());
        activitiService.claim(taskId, staffId.toString());
        activitiService.setTaskVars(taskId, data);
        User staff = userService.findById(staffId);
        Note note = new Note();
        note.setRecordId(recordId);
        if (self){
            note.setStaff(staff.getUsername());
            note.setRemark(CLAIM_TIP);
        }else {
            Record record = recordService.findById(recordId);
            Area area = areaService.findById(record.getArea());
            User manager = userService.findById(area.getManager());
            note.setStaff(manager.getUsername());
            note.setRemark(delegateTip(staff));
        }

        note(taskId, recordId, note, null);
        handlerRe.claim(recordId);
    }

    @Transactional(rollbackFor = Exception.class)
    public void unclaim(String taskId, Long recordId, Boolean self) throws Exception {
        Task task = activitiService.getTaskById(taskId);
        User staff = userService.findById(task.getAssignee());
        Note note = new Note();
        note.setRecordId(recordId);
        if (self){
            note.setStaff(staff.getUsername());
            note.setRemark(UNCLAIM_TIP);
        }else {
            Record record = recordService.findById(recordId);
            Area area = areaService.findById(record.getArea());
            User manager = userService.findById(area.getManager());
            note.setStaff(manager.getUsername());
            note.setRemark(transferTip(staff));
        }
        note(taskId, recordId, note, null);
        activitiService.unclaim(taskId);
        handlerRe.unclaim(Long.valueOf(task.getAssignee()), recordId);
    }

    @Transactional(rollbackFor = Exception.class)
    public void note(String taskId, Long recordId, Note note, String[] urls) throws Exception {
        String notes = activitiService.getTaskVar(taskId, "notes", String.class);
        noteService.save(note);
        saveBindingNotePhoto(note, urls);
        if (notes == null) {
            notes = note.getRecordId().toString();
        } else {
            notes += "," + note.getRecordId();
        }
        activitiService.setTaskVar(taskId, "notes", notes);
        handlerRe.note(recordId);
    }

    @Transactional(rollbackFor = Exception.class)
    public void complete(String taskId, Long recordId, Note note, boolean success, String[] urls) throws Exception {
        String notes = activitiService.getTaskVar(taskId, "notes", String.class);
        noteService.save(note);
        if (notes == null) {
            notes = note.getRecordId().toString();
        } else {
            notes += "," + note.getRecordId();
        }
        saveBindingNotePhoto(note, urls);
        activitiService.setTaskVar(taskId, "success", success);
        activitiService.setTaskVar(taskId, "notes", notes);
        activitiService.complete(taskId);
        handlerRe.complete(recordId);
    }

    private void saveBindingNotePhoto(Note note, String[] urls) throws Exception {
        if (urls != null) {
            for (String url : urls) {
                RecordPhoto photo = new RecordPhoto();
                photo.setUrl(url);
                photo.setNoteId(note.getId());
                recordPhotoService.save(photo);
            }
        }
    }

    public List<RepairProcDto> selectCandidateTask(Long assignee) throws Exception {
        List<Task> taskList = activitiService.getUserTaskByCandidate(assignee.toString());
        List<ProcessInstance> procs = activitiService.getProcByTasks(taskList);
        List<RepairProcDto> dtos = new LinkedList<>();
        for (ProcessInstance p : procs) {
            List<RepairTaskDto> taskDtoss = poToDto.taskDtoList(activitiService.getTasksByProc(p.getProcessInstanceId()));
            dtos.add(new RepairProcDto(p, taskDtoss, p.getProcessVariables()));
        }
        return dtos;
    }

    public RepairProcDto selectProcByRecordId(Long recordId, User cUser, String openId) throws Exception {
        HistoricVariableInstance var = activitiService.getVarByNameAndValue("recordId", recordId);
        if (var == null) {
            return null;
        }
        RepairProcDto dto = selectProcById(var.getProcessInstanceId());
        Record record = recordService.findById(recordId);
        if (record == null) {
            return null;
        }
        if(isRelative(cUser, openId, record)) {
            return dto;
        }
        return null;
    }

    private boolean isManagerOrStaff(User cUser, Record record) {
        Area area = areaService.findById(record.getArea());
        return Objects.equals(cUser.getId(), area.getManager())
                || StringTool.strings2LongList(area.getStaffs()).contains(cUser.getId());
    }

    private boolean isRegistrant(String openId, Record record){
        return openId.equals(record.getWechatOpenid());
    }

    private boolean isRelative(User cUser, String openId, Record record) {
        if(cUser == null) {
            return isRegistrant(openId, record);
        }
        return isManagerOrStaff(cUser, record);
    }

    public List<RepairProcDto> listHistory(User cUser, String openId, Date after, Date before, Boolean finished) throws Exception {
        Set<String> procIds = null;
        if(cUser!=null){
            if (cUser.getRole().equals(ConstantRole.ROLE_MANAGER)){
                List<Area> areas = areaService.listOrByExample(Area.builder().manager(cUser.getId()).build(), null).getResults();
                List<Long> areaIds = new LinkedList<>();
                for(Area area : areas){
                    areaIds.add(area.getId());
                }
                List<Record> records = recordService.listByAreaIds(areaIds);
                List<Long> recordIds = new LinkedList<>();
                for(Record record : records){
                    recordIds.add(record.getId());
                }
                procIds = activitiService.listHistoryProcIdByVarNameAndValueList("recordId", recordIds);
            }
            if (cUser.getRole().equals(ConstantRole.ROLE_STAFF)){                
                procIds = activitiService.listHistoryProcIdByAssignee(cUser.getId().toString());
            }
        } else if (StringUtils.isNotBlank(openId)){
            List<Record> records = recordService.listOrByExample(Record.builder().wechatOpenid(openId).build(), null).getResults();
            List<Long> recordIds = new LinkedList<>();
            for(Record record : records){
                recordIds.add(record.getId());
            }
            procIds = activitiService.listHistoryProcIdByVarNameAndValueList("recordId", recordIds);
        }
        List<HistoricProcessInstance> procs = activitiService.listHistoryProcByIdSetAndDateRangeAndFinished(procIds, after, before, finished);
        return poToDto.repairProcDtoList(procs);
    }

    private RepairProcDto selectProcById(String id) throws Exception {
        HistoricProcessInstance h = activitiService.selectHistoryProcById(id);
        return poToDto.repairProcDto(h);
    }

    private String delegateTip(User staff){
        return "指定了"+staff.getUsername()+"来接手";
    }

    private String transferTip(User staff){
        return "调离了"+staff.getUsername();
    }
}
